package com.mock.ems.common;

import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.IAtom;
import com.jfinal.plugin.activerecord.Record;
import com.mock.base.util.ArithUtil;
import com.mock.base.util.CollectionUtil;
import com.mock.base.util.DateUtil;
import com.mock.base.util.NumberUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Created by MOCK on 2017/8/17.
 */
public class DistributionHandler {

    private static final Logger logger = LoggerFactory.getLogger(DistributionHandler.class);

    public static void handle(Map<String,Object> orderMap) {

        Long userId = NumberUtil.toLong(orderMap.get("partyId"));
        if (null == userId) {
            logger.error("userId from orderMap is null");
            return;
        }

        //
        List<Map<String,Object>> orderList = (List<Map<String, Object>>) orderMap.get("soItemParamViews");
        if (CollectionUtil.isEmpty(orderList)) {
            logger.error("orderList from orderMap is empty");
            return;
        }

        String orderIdStr = String.valueOf(orderMap.get("soId"));
        Long orderId = NumberUtil.toLong(orderIdStr);

        String checkConsumeSQL = "select * from t_gl_topic where entity_id_ = ? and key_type_ = ? ";
        logger.info("Db.use()==>{}",Db.use());
        Record glTopicRecord = Db.findFirst(checkConsumeSQL,orderIdStr,"reids.publish.addSoEntity");
        if (null != glTopicRecord) {
            if ("consumeded".equals(glTopicRecord.get("status_"))) {
                logger.info("order has already consume");
                return;
            }
        }

        //包裹在事务中执行
        Db.tx(new IAtom() {
            @Override
            public boolean run() throws SQLException {
                doHandle(orderList,orderId,glTopicRecord,userId);
                return true;
            }
        });
    }

    private static void doHandle(List<Map<String,Object>> orderList,Long orderId,Record glTopicRecord,Long userId) {

        for (Map<String,Object> order : orderList) {

            String shopId = String.valueOf(order.get("shopId"));
            Record merchantRatio =
                    Db.findFirst("select * from distribution_merchant_ratio where merchant_id = ? and status = 1",shopId);
            if (null == merchantRatio) {
                logger.error("merchantRatio is NULL. shopId:{}",shopId);
                continue;
            }

            //查找分成配置表
            Long ratio_id = merchantRatio.getLong("ratio_id");
            Record distributionRatioConfigRecord = Db.findById("distribution_ratio_config",ratio_id);
            if (null == distributionRatioConfigRecord) {
                logger.error("distributionRatioConfigRecord is NULL.ratio_id:{}",ratio_id);
                continue;
            }


            Double selfPrice = NumberUtil.toDouble(order.get("shopListPrice"));
            if (null == selfPrice || selfPrice <= 0) {
                logger.error("selfPrice is NULl or selfPrice less than 0.selfPrice:{}",selfPrice);
                continue;
            }

            //查找商家对应用户
            Record shopRecord = Db.findById("t_ou_shop","id_",shopId);
            if (null == shopRecord) {
                logger.error("shopRecord is NULL.shopId:{}",shopId);
                continue;
            }

            Long shopOwnnerId = NumberUtil.toLong(shopRecord.get("party_id_"));
            Double ratio = merchantRatio.getDouble("ratio");

            List<Map<String,Object>> saleSkuViews = (List<Map<String, Object>>) order.get("saleSkuViews");
            if (CollectionUtil.isEmpty(saleSkuViews)) {
                logger.error("saleSkuViews List is Empty.shopId:{}",shopId);
                continue;
            }

            //商家
            merchantHandler(merchantRatio,shopOwnnerId,shopId,orderId,userId,selfPrice);

            //消费者
            consumerHandler(distributionRatioConfigRecord,saleSkuViews,userId,orderId,selfPrice,ratio);

            //消费商
            recommaderHandler(distributionRatioConfigRecord,userId,orderId,selfPrice,ratio);

            //合作伙伴
            Long partnerId = cooperationPartnerHandler(distributionRatioConfigRecord,shopOwnnerId,orderId,selfPrice,ratio);

            //服务中心
            serviceCenterHandler(distributionRatioConfigRecord,partnerId,orderId,selfPrice,ratio);

            //区县代理
            areaAgentHandler(shopOwnnerId,orderId,selfPrice);

            //平台
            platformHandler(distributionRatioConfigRecord,userId,orderId,selfPrice,ratio);

            //后续更新
            if (glTopicRecord != null) {
                glTopicRecord.set("consumed_time_",new Date());
                glTopicRecord.set("status_","consumeded");
                if (!Db.update("t_gl_topic","id_",glTopicRecord)) {
                    throw new RuntimeException("update t_gl_topic error!");
                }
            }
            logger.info("handle order succeed.");
        }
    }

    private static boolean merchantHandler(Record merchantRatio,Long shopOwnnerId,String shopId,Long orderId,Long userId,Double selfPrice)  {

        //商家让利比
        Double ratio = merchantRatio.getDouble("ratio");
        Double sg_merchant_ratio = merchantRatio.getDouble("sg_merchant_ratio");
        Double sg_merchant_factor = merchantRatio.getDouble("sg_merchant_factor");


        if (null == shopOwnnerId) {
            logger.error("shopOwnnerId is NULL");
            return false;
        }

        Double merchantGetAmount = ArithUtil.mul(selfPrice,(ArithUtil.sub(1.0,ratio)));
        Double merchantGetScore = ArithUtil.mul(selfPrice,sg_merchant_ratio*sg_merchant_factor);

        logger.info("selfPrice:{},sg_merchant_factor{},sg_merchant_ratio:{},ratio:{},merchantGetScore:{}",
                new Object[]{selfPrice,sg_merchant_factor,sg_merchant_ratio,ratio,merchantGetScore});

        //更新商家对应的用户账户
        String updateMerChantSQL = "update user_account set balance = balance + " + merchantGetAmount + ",score = score + "
                + merchantGetScore + ",total_income = total_income + " + merchantGetAmount + " where user_id = ? ";
        if (Db.update(updateMerChantSQL,shopOwnnerId) <= 0 ) {
            throw new RuntimeException("update merchant user_account fail");
        }
        //添加商家分润明细
        Record merchantDetailRecord = new Record();
        merchantDetailRecord.set("merchant_id",shopId)
                .set("user_id",shopOwnnerId)
                .set("order_id",orderId)
                .set("amount",selfPrice)
                .set("ratio",ratio)
                .set("income",merchantGetAmount)
                .set("score",merchantGetScore)
                .set("sg_merchant_ratio",merchantGetScore)
                .set("sg_merchant_factor",sg_merchant_factor)
                .set("create_time",new Date())
                .set("status",1);
        if (!Db.save("distribution_merchant_detail",merchantDetailRecord)) {
            throw new RuntimeException("save distribution_merchant_detail error");
        }

        //添加统计信息
        Record merchantDayCountRecord =
                Db.findFirst("select * from distribution_merchant_day_count where user_id = ? and shop_id = ? " +
                        " and time > ? ",shopOwnnerId,shopId,DateUtil.toSeconds(DateUtil.getCurrentBeginTime().getTime()));
        if (null == merchantDayCountRecord) {
            merchantDayCountRecord = new Record();
            merchantDayCountRecord.set("user_id",shopOwnnerId)
                    .set("shop_id",shopId)
                    .set("total_amount",selfPrice)
                    .set("total_income",merchantGetAmount)
                    .set("total_score",merchantGetScore)
                    .set("total_count",1)
                    .set("total_outcome",ArithUtil.sub(selfPrice,merchantGetAmount))
                    .set("time", DateUtil.currentTimeSeconds())
                    .set("status",1);
            if (!Db.save("distribution_merchant_day_count",merchantDayCountRecord)) {
                throw new RuntimeException("save distribution_merchant_day_count error!");
            }
        }else {
            merchantDayCountRecord
                    .set("total_amount",ArithUtil.add(merchantDayCountRecord.getDouble("total_amount"),selfPrice));
            merchantDayCountRecord
                    .set("total_income",ArithUtil.add(merchantDayCountRecord.getDouble("total_income"),merchantGetAmount));
            merchantDayCountRecord.set("total_score",ArithUtil.add(merchantDayCountRecord.getDouble("total_score"),merchantGetScore));
            merchantDayCountRecord.set("total_count",merchantDayCountRecord.getInt("total_count") + 1);
            merchantDayCountRecord
                    .set("total_outcome",ArithUtil.add(merchantDayCountRecord.getDouble("total_outcome"),ArithUtil.sub(selfPrice,merchantGetAmount)));

            merchantDayCountRecord.set("time",DateUtil.currentTimeSeconds());
            if (!Db.update("distribution_merchant_day_count",merchantDayCountRecord)) {
                throw new RuntimeException("update distribution_merchant_day_count fail");
            }
        }

        fundsDetailHandle(shopOwnnerId,merchantGetAmount);
        scoreDetailHandle(shopOwnnerId,userId,merchantGetScore);
        return true;
    }

    private static void consumerHandler(Record distributionRatioConfigRecord,List<Map<String,Object>> saleSkuViews,Long userId,Long orderId,Double selfPrice,Double ratio) {

        //更新消费者
        Double fr_consumer_ratio = distributionRatioConfigRecord.getDouble("fr_consumer_ratio");
        Double fr_consumer_factor = distributionRatioConfigRecord.getDouble("fr_consumer_factor");

        //Double sg_consumer_ratio = distributionRatioConfigRecord.getDouble("sg_consumer_ratio");
        Double sg_consumer_factor = distributionRatioConfigRecord.getDouble("sg_consumer_factor");

        Double consumerGetAmount = ArithUtil.mul(selfPrice,
                ArithUtil.mul(fr_consumer_ratio,fr_consumer_factor));

        Double consumerGetScore = 0.00;

        for (Map<String,Object> item : saleSkuViews) {
            //积分比例
            Double scoreRatio = NumberUtil.toDouble(item.get("pointProportion"));
            if (null == scoreRatio) {
                continue;
            }

            Double singlePrice = NumberUtil.toDouble(item.get("listPrice"));
            if (null == scoreRatio) {
                continue;
            }

            //Double rationFactor = ArithUtil.mul(scoreRatio,sg_consumer_factor);
            //if (scoreRatio == 0.7) rationFactor = 4.0;
            //if (scoreRatio == 0.8) rationFactor = 5.0;
            Double singleConsumerGetScore = ArithUtil.mul(singlePrice,scoreRatio);
            consumerGetScore = ArithUtil.add(consumerGetScore,singleConsumerGetScore);

            //计算算法太灵活，暂时写死
            if (scoreRatio <= 0.10) {
                consumerGetScore = ArithUtil.sub(consumerGetScore,
                        ArithUtil.mul(singlePrice,0.1*0.25));
            }else {
                consumerGetScore = ArithUtil.sub(consumerGetScore,
                        ArithUtil.mul(singlePrice,0.05));
            }

            logger.info("singlePrice:{},sg_consumer_ratio:{},sg_consumer_factor{},ratio:{},consumerGetScore:{}",
                    new Object[]{singlePrice,scoreRatio,sg_consumer_factor,ratio,consumerGetScore});

        }

        logger.info("selfPrice:{},fr_consumer_ratio:{},fr_consumer_factor{},ratio:{},consumerGetAmount:{}",
                new Object[]{selfPrice,fr_consumer_ratio,fr_consumer_factor,ratio,consumerGetAmount});

        String updateConsumerSQL = "update user_account set balance = balance + " + consumerGetAmount +
                ",score = score + " + consumerGetScore +
                ",total_income = total_income + " + consumerGetAmount +
                ",total_cost = total_cost + " + selfPrice +
                " where user_id = ? ";
        if(Db.update(updateConsumerSQL,userId) <= 0) {
            throw new RuntimeException("update consumer account fail");
        }
        Record consumerDetailRecord = new Record();
        consumerDetailRecord.set("user_id",userId)
                .set("order_id",orderId)
                .set("amount",selfPrice)
                .set("ratio",ratio)
                .set("income",consumerGetAmount)
                .set("score",consumerGetScore)
                .set("fr_consumer_ratio",fr_consumer_ratio)
                .set("fr_consumer_factor",fr_consumer_factor)
                .set("sg_consumer_ratio",consumerGetScore)
                .set("sg_consumer_factor",sg_consumer_factor)
                .set("create_time",new Date())
                .set("status",1);
        if (!Db.save("distribution_consumer_detail",consumerDetailRecord)) {
            throw new RuntimeException("save distribution_consumer_detail fail");
        }

        //添加名细
        fundsDetailHandle(userId,consumerGetAmount);

        scoreDetailHandle(userId,userId,consumerGetScore);

    }

    private static void recommaderHandler(Record distributionRatioConfigRecord,Long userId,Long orderId,Double selfPrice,Double ratio) {

        //查找消费商
        String userRelationSQL="select related_id from user_relation where user_id = ? and role = 1";
        Long recommanderId=Db.queryLong(userRelationSQL,userId);
        if(null != recommanderId) {
            Double fr_recommender_ratio=distributionRatioConfigRecord.getDouble("fr_recommender_ratio");
            Double fr_recommender_factor=distributionRatioConfigRecord.getDouble("fr_recommender_factor");

            Double recommanderGetAmount=ArithUtil.mul(selfPrice,
            ArithUtil.mul(fr_recommender_ratio,fr_recommender_factor));

            String updateRecommanderSQL="update user_account set " +
                    " balance = balance + "+recommanderGetAmount+
                    " ,total_income = total_income + " + recommanderGetAmount + " where user_id = ? ";
            if (Db.update(updateRecommanderSQL,recommanderId)<=0) {
            throw new RuntimeException("update recommander account user_account fail");
            }

            //添加消费商分成明细
            Record recommanderDetailRecord=new Record();
            recommanderDetailRecord.set("user_id",recommanderId)
            .set("order_id",orderId)
            .set("amount",selfPrice)
            .set("ratio",ratio)
            .set("income",recommanderGetAmount)
            .set("fr_recommander_ratio",fr_recommender_ratio)
            .set("fr_recommander_factor",fr_recommender_factor)
            .set("create_time",new Date())
            .set("status",1);
            if(!Db.save("distribution_recommander_detail",recommanderDetailRecord)){
                throw new RuntimeException("save distribution_recommander_detail error");
            }

            fundsDetailHandle(recommanderId,recommanderGetAmount);
        }
    }

    private static Long cooperationPartnerHandler(Record distributionRatioConfigRecord,Long shopOwnnerId,Long orderId,Double selfPrice,Double ratio) {
        //查找品牌合作伙伴
        Long partnerId = Db.queryLong("select related_id from user_relation where user_id = ? and role = 2",shopOwnnerId);
        logger.info("shopOwnnerId:{},partnerId:{}",shopOwnnerId,partnerId);
        if (null != partnerId) {
            Double fr_cooperation_partner_ratio = distributionRatioConfigRecord.getDouble("fr_cooperation_partner_ratio");
            Double fr_cooperation_partner_factor = distributionRatioConfigRecord.getDouble("fr_cooperation_partner_factor");

            Double partnerGetAmount = ArithUtil.mul(selfPrice,
                    ArithUtil.mul(fr_cooperation_partner_ratio,fr_cooperation_partner_factor));
            String updatePartnerSQL = "update user_account " +
                    " set balance = balance + " + partnerGetAmount +
                    " ,total_income = total_income + " + partnerGetAmount + " where user_id = ? ";
            logger.info("user_id:{},partnerId:{},partnerGetAmount:{}",shopOwnnerId,partnerId,partnerGetAmount);
            if (Db.update(updatePartnerSQL,partnerId) <=0) {
                throw new RuntimeException("update partner user_account fail");
            }

            //添加品牌合作伙伴的分成明细
            Record partnerDetailRecord = new Record();
            partnerDetailRecord.set("user_id",partnerId)
                    .set("order_id",orderId)
                    .set("amount",selfPrice)
                    .set("ratio",ratio)
                    .set("income",partnerGetAmount)
                    .set("fr_cooperation_partner_ratio",fr_cooperation_partner_ratio)
                    .set("fr_cooperation_partner_factor",fr_cooperation_partner_factor)
                    .set("create_time",new Date())
                    .set("status",1);
            if (!Db.save("distribution_cooperation_partner_detail",partnerDetailRecord)) {
                throw new RuntimeException("save distribution_cooperation_partner_detail fail");
            }

            fundsDetailHandle(partnerId,partnerGetAmount);
        }
        return partnerId;
    }

    private static void serviceCenterHandler(Record distributionRatioConfigRecord,Long partnerId,Long orderId,Double selfPrice,Double ratio) {

        //查找服务中心
        Long serviceCenterId = Db.queryLong("select related_id from user_relation where user_id = ? and role = 3 ",partnerId);
        logger.info("partnerId:{},serviceCenterId:{}",partnerId,serviceCenterId);
        if (null != serviceCenterId) {
            Double fr_service_center_ratio = distributionRatioConfigRecord.getDouble("fr_service_center_ratio");
            Double fr_service_center_factor = distributionRatioConfigRecord.getDouble("fr_service_center_factor");

            Double serviceCenterGetAmount = ArithUtil.mul(selfPrice,
                    ArithUtil.mul(fr_service_center_ratio, fr_service_center_factor));
            String updateServiceCenterSQL = "update user_account set balance = balance + " + serviceCenterGetAmount + " " +
                    " ,total_income = total_income + "+serviceCenterGetAmount+" where user_id = ? ";
            logger.info("partnerId:{},serviceCenterId:{},serviceCenterGetAmount:{}",partnerId,serviceCenterId,serviceCenterGetAmount);
            if (Db.update(updateServiceCenterSQL, serviceCenterId) <= 0) {
                throw new RuntimeException("update service_center user_account fail");
            }
            //添加服务中心分成明细
            Record serviceCenterDetailRecord = new Record();
            serviceCenterDetailRecord.set("user_id", serviceCenterId)
                    .set("order_id", orderId)
                    .set("amount", selfPrice)
                    .set("ratio", ratio)
                    .set("income", serviceCenterGetAmount)
                    .set("fr_service_center_ratio", fr_service_center_ratio)
                    .set("fr_service_center_factor", fr_service_center_factor)
                    .set("create_time", new Date())
                    .set("status", 1);
            if (!Db.save("distribution_service_center_detail", serviceCenterDetailRecord)) {
                throw new RuntimeException("save distribution_service_center_detail fail");
            }

            fundsDetailHandle(serviceCenterId,serviceCenterGetAmount);
        }
    }

    private static void platformHandler(Record distributionRatioConfigRecord,Long userId,Long orderId,Double selfPrice,Double ratio) {

        Double fr_consumer_ratio = distributionRatioConfigRecord.getDouble("fr_consumer_ratio");
        Double fr_consumer_factor = distributionRatioConfigRecord.getDouble("fr_consumer_factor");

        Double consumerGetAmount = ArithUtil.mul(selfPrice,
                ArithUtil.mul(fr_consumer_ratio,fr_consumer_factor));

        Double fr_recommender_ratio=distributionRatioConfigRecord.getDouble("fr_recommender_ratio");
        Double fr_recommender_factor=distributionRatioConfigRecord.getDouble("fr_recommender_factor");

        Double recommanderGetAmount=ArithUtil.mul(selfPrice,
                ArithUtil.mul(fr_recommender_ratio,fr_recommender_factor));

        Double fr_cooperation_partner_ratio = distributionRatioConfigRecord.getDouble("fr_cooperation_partner_ratio");
        Double fr_cooperation_partner_factor = distributionRatioConfigRecord.getDouble("fr_cooperation_partner_factor");

        Double partnerGetAmount = ArithUtil.mul(selfPrice,
                ArithUtil.mul(fr_cooperation_partner_ratio,fr_cooperation_partner_factor));

        Double fr_service_center_ratio = distributionRatioConfigRecord.getDouble("fr_service_center_ratio");
        Double fr_service_center_factor = distributionRatioConfigRecord.getDouble("fr_service_center_factor");

        Double serviceCenterGetAmount = ArithUtil.mul(selfPrice,
                ArithUtil.mul(fr_service_center_ratio, fr_service_center_factor));

        Double outcome = ArithUtil.add(
                ArithUtil.add(consumerGetAmount,recommanderGetAmount),
                ArithUtil.add(partnerGetAmount,serviceCenterGetAmount)
        );

        Record platformDetailRecord = new Record();
        platformDetailRecord.set("user_id",userId)
                .set("order_id",orderId)
                .set("ratio",ratio)
                .set("amount",selfPrice)
                .set("income",ArithUtil.mul(selfPrice,ratio))
                .set("outcome",outcome)
                .set("create_time",new Date())
                .set("status",1);
        if (!Db.save("distribution_platform_detail",platformDetailRecord)) {
            throw new RuntimeException("save distribution_platform_detail fail");
        }
    }

    private static void areaAgentHandler(Long shopOwnerId,Long orderId,Double selfPrice) {

        //查看商家是否有区县代理，如果没有则不进行处理
        Long area_user_id = Db.queryLong("select area_user_id from distribution_merchant_areaagent_relation where merchant_user_id = ?",shopOwnerId);
        if (null == area_user_id) {
            logger.info("商家：{}，没有找到对应的区县代理。",shopOwnerId);
            return;
        }

        Record areaAgentRecord = Db.findFirst("select * from area_agent where user_id = ? and status = 1",area_user_id);
        if (null == areaAgentRecord) {
            logger.error("areaAgentRecord is NULL. userId:{}",area_user_id);
            return;
        }
        Double ratio = areaAgentRecord.getDouble("ratio");
        if (null == ratio) {
            logger.error("area agent ratio is null.");
            return;
        }

        Double areaAgentGetAmount = ArithUtil.mul(selfPrice,ratio);
        //更新
        String updateAreaAgentSQL = "update user_account set balance = balance + " + areaAgentGetAmount +
                ",total_income = total_income + " + areaAgentGetAmount + " where user_id = ? ";
        logger.info("shopOwnerId:{},area_user_id:{},areaAgentGetAmount:{}",shopOwnerId,area_user_id,areaAgentGetAmount);
        if (Db.update(updateAreaAgentSQL,area_user_id) <= 0) {
            throw new RuntimeException("update area_agent user_account fail");
        }

        Record areaAgentDetailRecord = new Record();
        areaAgentDetailRecord.set("order_id", orderId)
                .set("amount", selfPrice)
                .set("ratio", ratio)
                .set("income", areaAgentGetAmount)
                .set("user_id",area_user_id)
                .set("create_time",new Date())
                .set("status",1);
        if (!Db.save("distribution_area_agent_detail",areaAgentDetailRecord)) {
            throw new RuntimeException("save distribution_area_agent_detail fail");
        }

        fundsDetailHandle(area_user_id,areaAgentGetAmount);
    }

    private static void scoreDetailHandle(Long userId,Long orderUserId,Double amount) {

        Record record = new Record();
        String extAction = "";
        if (null != orderUserId) {
            String nickName = Db.queryStr("select nick_name from user where id = ? ",orderUserId);
            extAction = "{\"nickName\":\""+nickName+"\"}";
        }

        record.set("user_id",userId)
                .set("action","分润收入")
                .set("ext_action",extAction)
                .set("amount",amount)
                .set("type",4)
                .set("status",1)
                .set("create_time",new Date());
        if (!Db.save("user_score_record",record)) {
            throw new RuntimeException("save user_score_record fail");
        }

    }

    private static void fundsDetailHandle(Long userId,Double amount) {

        String nanoTime = String.valueOf(System.nanoTime());
        String orderNo = DateUtil.format(new Date(),"yyyyMMddHHmmss")
                + nanoTime.substring(nanoTime.length() - 5,nanoTime.length());
        Record record = new Record();
        record.set("user_id",userId)
                .set("action","分润收入")
                .set("ext_action","")
                .set("order_no",orderNo)
                .set("type",4)
                .set("amount",amount)
                .set("create_time",new Date());
        if (!Db.save("user_funds_record",record)) {
            throw new RuntimeException("save user_funds_record fail");
        }
    }
}
